package com.woniu.service.impl;

import cn.hutool.extra.qrcode.QrCodeUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.woniu.constants.ErrorConstants;
import com.woniu.constants.RedisConstants;
import com.woniu.constants.WeChatConstants;
import com.woniu.entity.*;
import com.woniu.exception.MyErrorException;
import com.woniu.form.SendWishForm;
import com.woniu.form.SetOffFireworksForm;
import com.woniu.mapper.*;
import com.woniu.service.*;
import com.woniu.utils.*;
import com.woniu.vo.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import sun.misc.BASE64Encoder;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @Description:
 * @Author: woniu
 * @date: 2023/12/21 14:01
 */
@Service
@EnableAsync
public class FireworksServiceImpl extends ServiceImpl<FireworksMapper, Fireworks> implements FireworksService {

    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private TokenUtil tokenUtil;

    @Autowired
    private FireworksMapper fireworksMapper;

    @Autowired
    private NuserService nuserService;

    @Autowired
    private NuserShareMapper nuserShareMapper;

//    @Autowired
//    private FireworksConfigService fireworksConfigService;

    @Autowired
    private FireworksConfigMapper fireworksConfigMapper;

    @Autowired
    private WishConfigMapper wishConfigMapper;

    @Autowired
    private BlessingConfigMapper blessingConfigMapper;

    @Autowired
    private InviteFireworksRecordMapper inviteFireworksRecordMapper;

    @Autowired
    private NuserSubscriptionMapper nuserSubscriptionMapper;

    @Autowired
    private RedPacketPoolMapper redPacketPoolMapper;

    @Autowired
    private WechatService wechatService;

    @Autowired
    private WechatTemplateMessageService wechatTemplateMessageService;

    @Autowired
    private TransactionTemplate transactionTemplate;


    /**
     * 记录观看视频次数
     * @return
     */
    @Override
    public boolean recordWatchVideoNum() {
        String userId = tokenUtil.getUserId();
        String watchVideoKey = RedisConstants.USER_WATCH_VIDEO + userId;

        // key存在，则自增1
        if (redisUtil.exists(watchVideoKey)){
            redisUtil.setIncrement(watchVideoKey,(long)1);
            return true;
        }
        // 计算距离0点的结束时间
        Long timeLeft = TimeUtil.calculateTime();
        redisUtil.setString(watchVideoKey,timeLeft);

        return true;
    }

    /**
     * 查询观看视频次数
     * @return
     */
    @Override
    public String findWatchVideoNum() {
        String userId = tokenUtil.getUserId();
        String watchVideoKey = RedisConstants.USER_WATCH_VIDEO + userId;

        String num = redisUtil.getString(watchVideoKey);
        if (StringUtils.isEmpty(num)){
            num = "0";
        }
        return num;
    }

    /**
     * 燃放烟花
     * @param form x,y坐标,烟花类型ID
     * @return
     */
    @Override
    public SetOffFireworksVO setOffFireworks(SetOffFireworksForm form) {
        String userId = tokenUtil.getUserId();

        Nuser nuser = nuserService.getById(userId);
        if (nuser == null){
            throw new MyErrorException(ErrorConstants.USER_IS_NULL);
        }

        // 查询烟花类型是否存在
        FireworksConfig fireworksConfig = fireworksConfigMapper.selectById(form.getFConfigId());
        if (fireworksConfig == null){
            throw new MyErrorException(ErrorConstants.FIREWORKS_CONFIG_IS_NULL);
        }

        // 先给用户随机一个愿望，然后等用户自己发射愿望了再去更新。
        WishConfigVO wishConfigVO = wishConfigMapper.findRandomVO();

        Fireworks fireworks = Fireworks.builder()
                .fireworksConfigId(fireworksConfig.getId())
                .xCoordinate(form.getX())
                .yCoordinate(form.getY())
                .nuserId(nuser.getId())
                .wishConfigId(wishConfigVO.getWishId()).build();
        boolean userUpdate = false;
        // 用户首次燃放需要更改用户的首次燃放记录和烟花需要记录是首次燃放的
        if (!nuser.getFirstSetOff()){
            userUpdate = true;
            fireworks.setNewUserSetOff(true);
        }


        Boolean flag;
        if (userUpdate){

            // 更新用户和新增燃放烟花
            flag = transactionTemplate.execute(e -> {

                if (fireworksMapper.insert(fireworks) <= 0) {
                    return Boolean.FALSE;
                }

                nuserService.update(null, new LambdaUpdateWrapper<Nuser>()
                        .eq(Nuser::getId, nuser.getId())
                        .set(Nuser::getFirstSetOff, true));

                // 如果用户有分享人的情况下，则查询对方是否有燃放烟花且还未添加邀请的记录
                if (!StringUtils.isEmpty(nuser.getInviteUid())){
                    InviteFireworksRecord inviteFireworksRecord = inviteFireworksRecordMapper.selectOne(new LambdaQueryWrapper<InviteFireworksRecord>()
                            .eq(InviteFireworksRecord::getNuserId, nuser.getInviteUid())
                            .eq(InviteFireworksRecord::getSetOffFireworks, true)
                            .eq(InviteFireworksRecord::getInviteNewPeople, false)
                            .eq(InviteFireworksRecord::getRedPacketReceived, false)
                            .last(" limit 1"));
                    // 为null则新增
                    if (inviteFireworksRecord == null){
                        if (inviteFireworksRecordMapper.insert(InviteFireworksRecord.builder()
                                .inviteNewPeople(true)
                                .nuserId(nuser.getInviteUid())
                                .build()) <= 0){
                            return Boolean.FALSE;
                        }

                    }else {
                        inviteFireworksRecord.setInviteNewPeople(true);
                        if (inviteFireworksRecordMapper.updateById(inviteFireworksRecord) <= 0){
                            return Boolean.FALSE;
                        }
                    }


                }

                // 查询燃放记录
                InviteFireworksRecord newPeopleRecord = inviteFireworksRecordMapper.selectOne(new LambdaQueryWrapper<InviteFireworksRecord>()
                        .eq(InviteFireworksRecord::getNuserId, userId)
                        .eq(InviteFireworksRecord::getInviteNewPeople, true)
                        .eq(InviteFireworksRecord::getSetOffFireworks, false)
                        .eq(InviteFireworksRecord::getRedPacketReceived, false)
                        .last(" limit 1"));

                // 为null则添加新的燃放记录
                if (newPeopleRecord == null){
                    newPeopleRecord = InviteFireworksRecord.builder()
                            .setOffFireworks(true)
                            // 添加第一次燃放的标志
                            .firstSetOff(true)
                            .nuserId(userId).build();
                    if (inviteFireworksRecordMapper.insert(newPeopleRecord) <= 0){
                        return Boolean.FALSE;
                    }

                }else {
                    newPeopleRecord.setSetOffFireworks(true);
                    // 添加第一次燃放的标志
                    newPeopleRecord.setFirstSetOff(true);
                    if (inviteFireworksRecordMapper.updateById(newPeopleRecord) <= 0){
                        return Boolean.FALSE;
                    }
;
                }

                return Boolean.TRUE;

            });

        } else {

            flag = transactionTemplate.execute(e -> {

                if (fireworksMapper.insert(fireworks) <= 0){
                    return Boolean.FALSE;
                }

                // 查询燃放记录
                InviteFireworksRecord newPeopleRecord = inviteFireworksRecordMapper.selectOne(new LambdaQueryWrapper<InviteFireworksRecord>()
                        .eq(InviteFireworksRecord::getNuserId, userId)
                        .eq(InviteFireworksRecord::getInviteNewPeople, true)
                        .eq(InviteFireworksRecord::getSetOffFireworks, false)
                        .eq(InviteFireworksRecord::getRedPacketReceived, false)
                        .last(" limit 1"));

                // 为null则添加新的燃放记录
                if (newPeopleRecord == null){
                    newPeopleRecord = InviteFireworksRecord.builder().setOffFireworks(true).nuserId(userId).build();
                    if (inviteFireworksRecordMapper.insert(newPeopleRecord) <= 0){
                        return Boolean.FALSE;
                    }
                }else {
                    newPeopleRecord.setSetOffFireworks(true);
                    if (inviteFireworksRecordMapper.updateById(newPeopleRecord) <= 0){
                        return Boolean.FALSE;
                    }
                }

                return Boolean.TRUE;
            });

        }

        // 成功则redis记录成功次数和保存燃放记录
        if (Boolean.TRUE.equals(flag)){
            // redis key
            String watchVideoKey = RedisConstants.USER_WATCH_VIDEO + userId;

            // key存在，则自增1
            if (redisUtil.exists(watchVideoKey)){
                redisUtil.setIncrement(watchVideoKey,(long)1);
            }else {
                // 计算距离0点的结束时间
                Long timeLeft = TimeUtil.calculateTime();
                redisUtil.setString(watchVideoKey,timeLeft);
            }

            // 如果用户有邀请人且烟花是首次燃放则发送邀请结果订阅给邀请的用户
            if (!StringUtils.isEmpty(nuser.getInviteUid()) && userUpdate){
                // 异步操作
                sendInviteSub(nuser);
            }

//            // 查询燃放记录
//            InviteFireworksRecord inviteFireworksRecord = inviteFireworksRecordMapper.selectOne(new LambdaQueryWrapper<InviteFireworksRecord>()
//                    .eq(InviteFireworksRecord::getNuserId, userId)
//                    .eq(InviteFireworksRecord::getInviteNewPeople, true)
//                    .eq(InviteFireworksRecord::getSetOffFireworks, false)
//                    .eq(InviteFireworksRecord::getRedPacketReceived, false)
//                    .last(" limit 1"));
//
//            // 为null则添加新的燃放记录
//            if (inviteFireworksRecord == null){
//                inviteFireworksRecord = InviteFireworksRecord.builder().setOffFireworks(true).nuserId(userId).build();
//                inviteFireworksRecordMapper.insert(inviteFireworksRecord);
//            }else {
//                inviteFireworksRecord.setSetOffFireworks(true);
//                inviteFireworksRecordMapper.updateById(inviteFireworksRecord);
//            }

        }

        return SetOffFireworksVO.builder().fireWorksId(Boolean.TRUE.equals(flag) ? fireworks.getId() : 0).build();

    }

    /**
     * 异步发送邀请结果订阅消息
     * @param nuser 被邀请人
     */
    @Async
    public void sendInviteSub(Nuser nuser){
        int hour = LocalDateTime.now().getHour();
        // 只能在7-22点发送订阅
        if (hour < 7 || hour > 22){
            return;
        }

        // 查询邀请人的openid
        Nuser inviteNuser = nuserService.getById(nuser.getInviteUid());
        if (inviteNuser == null){
            return;
        }

        // 查询邀请人是否有订阅邀请结果
        if (!nuserSubscriptionMapper.exists(new LambdaQueryWrapper<NuserSubscription>()
                .eq(NuserSubscription::getNuserId,inviteNuser.getId())
                .eq(NuserSubscription::getTemplateId,WeChatConstants.WECHAT_TEMPLATE_INVITE))){
            return;
        }

        // 查询用户是否已超过发送次数限制,每天最多5次，每2小时最多一次
        // 总次数redis key
        String wechatSubInviteKey = RedisConstants.USER_PROGRAM_INVITE + inviteNuser.getId();
        // 两小时的redis key
        String wechatSubInviteTwoHourKey = RedisConstants.USER_PROGRAM_INVITE_TWO_HOUR + inviteNuser.getId();

        // 两小时内是否已经下发过
        if (redisUtil.exists(wechatSubInviteTwoHourKey)){
            return;
        }

        // 是否超过5次
        String subNum = redisUtil.getString(wechatSubInviteKey);
        if (!StringUtils.isEmpty(subNum) && Integer.parseInt(subNum) >= 5){
            return;
        }

        // 查询模板
        WechatTemplateMessage wechatTemplateMessage = wechatTemplateMessageService.getById(WeChatConstants.WECHAT_TEMPLATE_INVITE);
        if (wechatTemplateMessage == null){
            return;
        }

        HashMap<String, String> temMap = new HashMap<>();
        // 组装数据
        temMap.put("thing1", "放烟花 · 抢红包 · 过大年");
        temMap.put("name5","你的好友");
        temMap.put("thing10", "完成邀请任务，再放个烟花就能抢红包啦");
        // 发送订阅
        wechatService.pushMiniTemplateMessage(wechatTemplateMessage.getTempId(),temMap,inviteNuser.getOpenid());

        // 总次数key存在，则自增1
        if (redisUtil.exists(wechatSubInviteKey)) {
            redisUtil.setIncrement(wechatSubInviteKey, (long) 1);
        } else {
            // 计算距离0点的结束时间
            Long timeLeft = TimeUtil.calculateTime();
            redisUtil.setString(wechatSubInviteKey, timeLeft);
        }
        // 添加两小时key
        redisUtil.setString(wechatSubInviteTwoHourKey, 7200000L);
    }

    /**
     * 随机烟花
     * @return
     */
    @Override
    public List<FireworksConfigVO> randomFireworks(Integer num) {
        tokenUtil.getUserId();
        return fireworksConfigMapper.findRandomVO(num);
    }

    /**
     * 随机一个愿望
     * @return
     */
    @Override
    public WishConfigVO randomWish() {
        tokenUtil.getUserId();
        return wishConfigMapper.findRandomVO();
    }

    /**
     * 发射愿望
     * @param form 烟花ID，愿望ID
     * @return
     */
    @Override
    public boolean sendWish(SendWishForm form) {
        String userId = tokenUtil.getUserId();
        // 判断愿望是否存在
        if (!wishConfigMapper.exists(new LambdaQueryWrapper<WishConfig>()
                .eq(WishConfig::getId,form.getWishId()))){
            throw new MyErrorException(ErrorConstants.WISH_CONFIG_IS_NULL);
        }

        if (!fireworksMapper.exists(new LambdaQueryWrapper<Fireworks>()
                .eq(Fireworks::getId, form.getFireWorksId())
                .eq(Fireworks::getNuserId, userId))){
            throw new MyErrorException(ErrorConstants.FIREWORKS_IS_NULL);
        }

        return fireworksMapper.update(null,new LambdaUpdateWrapper<Fireworks>()
                .eq(Fireworks::getId,form.getFireWorksId())
                .eq(Fireworks::getNuserId,userId)
                .set(Fireworks::getWishConfigId,form.getWishId())) > 0;
    }

    /**
     * 燃放概况
     * @return
     */
    @Override
    public Long setOffGeneral() {
        tokenUtil.getUserId();
        return fireworksMapper.selectCount(new LambdaQueryWrapper<>());
    }

    /**
     * 随机获取一条祝福信息
     * @return
     */
    @Override
    public BlessingConfigVO randomBlessing() {
        tokenUtil.getUserId();
        return blessingConfigMapper.findRandomVO();
    }

    /**
     * 随机100个用户的愿望
     * @return
     */
    @Override
    public List<UserWishVO> randomUserWish() {
        tokenUtil.getUserId();
        return fireworksMapper.randomWishByUser();
    }

    /**
     * 获取用户分享二维码
     * @return
     */
    @Override
    public String shareQrcode() {
        String userId = tokenUtil.getUserId();

//        // 查询分享ID
//        NuserShare nuserShare = nuserShareMapper.selectOne(new LambdaQueryWrapper<NuserShare>()
//                .eq(NuserShare::getNuserId, userId));
//
//        // 分享ID为空则新增一个
//        if (nuserShare == null){
//            nuserShare = NuserShare.builder().nuserId(userId).build();
//            if (nuserShareMapper.insert(nuserShare) <= 0){
//                throw new MyErrorException(ErrorConstants.USER_IS_NULL);
//            }
//        }
        BufferedImage bufferedImage = QrCodeUtil.generate("http://ny.maishuren.com/pages/index/index?shareId="+userId, 120, 120);
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        try {
            ImageIO.write(bufferedImage,"png",bos);
        } catch (IOException e) {
            throw new MyErrorException(ErrorConstants.QRCODE_GEN_ERROR);
        }
        // 返回图片base64编码
        return BASE64Util.encoder(bos.toByteArray());
    }

    /**
     * 随机50个用户的愿望和50个3天内最大金额排序的红包
     * @return
     */
    @Override
    public UserWishAndRedPacketVO randomUserWishAndRedPacket() {
        tokenUtil.getUserId();

        // 随机愿望
        List<UserWishVO> userWishVOS = fireworksMapper.randomWishByUser();
        String theOtherDayDate = TimeUtil.getTheOtherDayDate(2);
        String nowEndDate = TimeUtil.getNowEndDate();

        // 50个飘屏红包
        List<UserRedPacketVO> userRedPacketVOS = new ArrayList<>();

        // 30个3天内最大金额排序的红包
        List<UserRedPacketMaxVO> userRedPacketMaxVOS = redPacketPoolMapper.findUserMaxRedPacketByDate(theOtherDayDate, nowEndDate);
        max : if (!CollectionUtils.isEmpty(userRedPacketMaxVOS)){
            List<Integer> redPacketIds = userRedPacketMaxVOS.stream().map(UserRedPacketMaxVO::getId).collect(Collectors.toList());
            if (CollectionUtils.isEmpty(redPacketIds)){
                break max;
            }

            for (UserRedPacketMaxVO userRedPacketMaxVO : userRedPacketMaxVOS) {
                UserRedPacketVO userRedPacketVO = ConverterUtil.convert(userRedPacketMaxVO, UserRedPacketVO.class);
                userRedPacketVOS.add(userRedPacketVO);
            }

            // 20个3天内最小金额红包排序的红包
            List<UserRedPacketVO> userRedPacketMinVOS = redPacketPoolMapper.findUserMinRedPacketByDate(theOtherDayDate, nowEndDate, redPacketIds);
            if (!CollectionUtils.isEmpty(userRedPacketMinVOS)){
                userRedPacketVOS.addAll(userRedPacketMinVOS);
            }

        }


        return UserWishAndRedPacketVO.builder()
                .userRedPacketVOS(CollectionUtils.isEmpty(userRedPacketVOS) ? new ArrayList<>() : userRedPacketVOS)
                .userWishVOS(CollectionUtils.isEmpty(userWishVOS) ? new ArrayList<>() : userWishVOS).build();
    }
}
